package com.yanghui.lingyue.bot

import com.icedata.sika.core.CommandProcessor
import com.icedata.sika.core.ParseProcessor
import com.icedata.sika.core.PreProcessor
import com.icedata.sika.core.Sika
import com.icedata.sika.launcher.Launcher
import com.icedata.sika.util.Logger
import com.yanghui.lingyue.bot.Bot.Companion.functionList
import com.yanghui.lingyue.bot.Bot.Companion.groupList
import com.yanghui.lingyue.bot.Bot.Companion.sikaCore
import com.yanghui.lingyue.bot.Bot.Companion.timeFunctionList
import com.yanghui.lingyue.bot.Bot.Companion.userList
import com.yanghui.lingyue.data.Command
import com.yanghui.lingyue.data.Function
import com.yanghui.lingyue.data.Group
import com.yanghui.lingyue.data.User
import com.yanghui.lingyue.functions.AbstractFunction
import com.yanghui.lingyue.functions.AbstractTimeFunction
import com.yanghui.lingyue.functions.Repeat
import com.yanghui.lingyue.functions.apiBase.SendAIReply
import com.yanghui.lingyue.functions.apiBase.SendMoePictures
import com.yanghui.lingyue.functions.apiBase.SendMotto
import com.yanghui.lingyue.functions.defaultFunction.AdministratorHandler
import com.yanghui.lingyue.functions.defaultFunction.BotPreprocessor
import com.yanghui.lingyue.functions.defaultFunction.NewUserFunction
import com.yanghui.lingyue.functions.defaultFunction.SendMessage
import com.yanghui.lingyue.functions.game.bread.Bread
import com.yanghui.lingyue.functions.ktBase.*
import com.yanghui.lingyue.functions.ktBase.qmLogic.QMLogic
import com.yanghui.lingyue.functions.python.BalanceChemistry
import com.yanghui.lingyue.functions.python.GetSatellitePosition
import com.yanghui.lingyue.functions.timer.SendTimerMessage
import com.yanghui.lingyue.functions.timer.TimeScheduler
import com.yanghui.lingyue.utils.databaseUtils.GroupDatabaseUtils
import kotlinx.coroutines.supervisorScope
import net.mamoe.mirai.event.GlobalEventChannel
import net.mamoe.mirai.event.events.MessageEvent

/**
 * Bot的实例，整个bot运行的核心
 * @property sikaCore Sika核心对象
 * @property groupList 通过数据库中的群组信息来获取群号和名字，不在这个群号中的方法一律过滤
 * @property userList 通过数据库中的用户信息来获取用户的各种信息
 * @property functionList 具体的初始化方法见 [com.yanghui.lingyue.core.functions.AbstractFunction] 中描述，总而言之首先在 functionList中装载方法，然后通过数据库检索方法名字，将解析方法和可行组注入进 function 中去
 * @property timeFunctionList 时间方法列表，直接通过名字装载可行组
 */
class Bot {

    companion object {
        var sikaCore: Sika = Sika("config/sika.config.json")
        var groupList: LinkedHashMap<Long, Group> = LinkedHashMap()
        var userList: LinkedHashMap<Long, User> = LinkedHashMap()
        var functionList: LinkedHashMap<String, AbstractFunction> = LinkedHashMap()
        var timeFunctionList: LinkedHashMap<String, AbstractTimeFunction> = LinkedHashMap()

        fun boot() {
            GroupDatabaseUtils.getGroupList().forEach {
                it.groupCache["SuccessiveRepeat"] = false
                it.groupCache["LastMessage"] = ""
                it.groupCache["OnActive"] = true
                groupList[it.groupID] = it
            }
            sikaCore.databaseCopy<Function>().let {
                it.forEach { f ->
                    f.init()
                    functionList[f.name]?.enableGroup?.clear()
                    functionList[f.name]?.enableGroup?.addAll(f.enableGroupList)
                }
            }
            sikaCore.databaseCopy<User>().forEach {
                userList[it.id] = it
            }
            Respond.init()
            Bread.init()
            SendTimerMessage.init()
            Repeat.init()
        }
    }

    private fun loadDefault() {

        /* TODO 任务注册接口，这些任务是静态任务，不会在运行过程中被动态加载 */
        functionList["SetBirthday"] = SetBirthday
        functionList["Repeat"] = Repeat
        functionList["Satellite"] = GetSatellitePosition
        functionList["Balance"] = BalanceChemistry
        functionList["RandCard"] = ArknightRandCard
        functionList["MoePic"] = SendMoePictures
        functionList["Motto"] = SendMotto
        functionList["DriftBottle"] = DriftBottle
        functionList["DriftBottleGlobal"] = DriftBottleGlobal
        functionList["LinePic"] = LinePicture
        functionList["Respond"] = Respond
        functionList["AIReply"] = SendAIReply
        functionList["Bread"] = Bread
        functionList["PornHigh"] = PornHigh
        functionList["Probability"] = Probability
        functionList["QMLogic"] = QMLogic
//        functionList["Game"] = GameEntry
        boot()

        // 启动定时任务
        TimeScheduler.start()

        // 挂载默认的方法
        sikaCore.mountPreProcessor(PreProcessor { event, sika ->
            BotPreprocessor.preprocess(event, sika)
        })
        sikaCore.mountParseProcessor(ParseProcessor(2000) { event, sika ->
            supervisorScope {
                try {
                    AdministratorHandler.parse(event, sika)
                } catch (e: Exception) {
                    Logger.logError(e)
                    listOf()
                }
            }
        })
        sikaCore.mountCommandProcessor(CommandProcessor(
            function = { command, sika ->
                try {
                    AdministratorHandler.execute(command as Command, sika)
                } catch (e: Exception) {
                    Logger.logError(e)
                    CommandProcessor.Result.BLOCK
                }
            }, 1000,
            filter = { command ->
                AdministratorHandler.filter(command as Command)
            }
        ))
        sikaCore.mountCommandProcessor(
            CommandProcessor(
                function = { command, sika ->
                    supervisorScope {
                        try {
                            SendMessage.execute(command as Command, sika)
                        } catch (e: Exception) {
                            Logger.logError(e)
                            CommandProcessor.Result.BLOCK
                        }
                    }
                },
                filter = { command ->
                    try {
                        SendMessage.filter(command as Command)
                    } catch (e: Exception) {
                        Logger.logError(e)
                        false
                    }
                })
        )
        sikaCore.mountParseProcessor(
            ParseProcessor(1000) { event, sika ->
                supervisorScope {
                    try {
                        NewUserFunction.parse(event, sika)
                    } catch (e: Exception) {
                        listOf<Command>()
                    }
                }
            }
        )
        sikaCore.mountCommandProcessor(
            CommandProcessor(
                function = { command, sika ->
                    supervisorScope {
                        try {
                            NewUserFunction.execute(command as Command, sika)
                        } catch (e: Exception) {
                            Logger.logError(e)
                            CommandProcessor.Result.BLOCK
                        }
                    }
                }, 1000,
                filter = { command ->

                    try {
                        NewUserFunction.filter(command as Command)
                    } catch (e: Exception) {
                        Logger.logError(e)
                        false
                    }

                })
        )
    }

    suspend fun launch() {
        val launcher = Launcher(sikaCore.config)
        sikaCore.init()
        loadDefault()
        // 挂载自定义的方法
        functionList.values.forEach {
            sikaCore.mountParseProcessor(ParseProcessor { event, sika ->
                supervisorScope {
                    try {
                        it.parse(event, sika)
                    } catch (e: Exception) {
                        listOf<Command>()
                    }
                }
            })
            sikaCore.mountCommandProcessor(
                CommandProcessor(
                    function = { command, sika ->
                        supervisorScope {
                            try {
                                it.execute(command as Command, sika)
                            } catch (e: Exception) {
                                Logger.logError(e)
                                CommandProcessor.Result.BLOCK
                            }
                        }
                    },
                    filter = { command ->
                        try {
                            it.filter(command as Command)
                        } catch (e: Exception) {
                            Logger.logError(e)
                            false
                        }
                    })
            )
        }

        timeFunctionList.values.forEach {
            sikaCore.delay(it.delay) { _ ->
                it.execute()
            }
        }
        GlobalEventChannel.subscribeAlways(MessageEvent::class) {
            sikaCore.newMessage(this)
        }
        launcher.launch()
    }
}